package com.vidmt.api.modules.sys.web;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.google.common.collect.Lists;
import com.thinkgem.jeesite.common.persistence.DataEntity;
import com.thinkgem.jeesite.modules.sys.utils.UserUtils;
import com.vidmt.api.common.anno.ApiDoc;
import com.vidmt.api.common.exceptions.CodeException;
import com.vidmt.api.common.pojo.ApiResultServer;
import com.vidmt.api.common.pojo.KV;
import com.vidmt.api.common.utils.CommUtil;
import com.vidmt.api.common.utils.PkgUtil;
import com.vidmt.api.common.web.ApiController;
import com.vidmt.api.modules.sys.entity.Location;
import com.vidmt.api.modules.sys.entity.Trace;
import com.vidmt.api.modules.sys.entity.User;

/**
 * 系统属性Controller
 * 
 * @author xingqisheng
 * @version 2015-08-14
 */
@Controller
@RequestMapping(value = "${adminPath}/web/sys/testapi")
public class WebTestApiController extends ApiController {
	private DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();

	private static final class ApiItem {
		public String url;
		public String[] params;
		public List<KV> paramDoc;
		public String method;
		public boolean cantest;
	}

	@RequestMapping(value = "/index.html")
	public String apitest(Model model) {
		Class<?> clz = CodeException.class;
		Field[] fields = clz.getDeclaredFields();
		List<String> list = new ArrayList<>();
		for (Field field : fields) {
			if (field.getName().startsWith("ERR_")) {
				field.setAccessible(true);
				try {
					list.add(field.getName() + "=" + field.get(null));
				} catch (Throwable e) {
					e.printStackTrace();
				}
			}
		}
		model.addAttribute("errcodes", list);
		return "modules/sys/testapi";
	}

	@ResponseBody
	@RequestMapping(value = "/getallapis.*")
	public ApiResultServer getAllApis() throws ClassNotFoundException {
		List<ApiItem> data = Lists.newArrayList();
		Set<Class<?>> classes = PkgUtil.getClassList("com.vidmt.api.modules.sys.api", false, Controller.class);
		for (Class<?> clz : classes) {
			String urlprefix = "";
			RequestMapping clzRmAnno = clz.getAnnotation(RequestMapping.class);
			if (clzRmAnno != null) {
				urlprefix = clzRmAnno.value()[0];
			}
			Method[] methods = clz.getMethods();
			for (Method mthd : methods) {
				RequestMapping rmAnno = mthd.getAnnotation(RequestMapping.class);
				if (rmAnno != null) {
					String url = urlprefix + rmAnno.value()[0];
					boolean canbetest = canTest(mthd, url);
					ApiItem item = new ApiItem();

					if (url != null) {
						item.url = url.replace(".*", ".json");
					}
					RequestMethod[] method = rmAnno.method();
					if (method != null && method.length > 0) {
						item.method = method[0].name();
					}

					item.params = buildParams(mthd);
					if (item.params.length == 0) {
						item.params = null;
					}
					item.paramDoc = buildParamDocs(mthd);
					item.cantest = canbetest;
					data.add(item);
				}

			}
		}
		Collections.sort(data, new Comparator<ApiItem>() {
			@Override
			public int compare(ApiItem o1, ApiItem o2) {
				return o1.url.compareTo(o2.url);
			}
		});
		return new ApiResultServer(data);
	}

	private List<KV> buildParamDocs(Method method) {
		ApiDoc[] docs = method.getAnnotationsByType(ApiDoc.class);
		if (!CommUtil.isEmpty(docs)) {
			List<KV> list = Lists.newArrayList();
			for (ApiDoc doc : docs) {
				String[] arr = doc.value();
				list.add(new KV(arr[0], arr[1]));
			}
			return list;
		}
		return null;
	}

	private String[] buildParams(Method method) {
		Class<?>[] ptypes = method.getParameterTypes();
		if (!CommUtil.isEmpty(ptypes)) {
			Class<?> clz = ptypes[0];
			if (CommUtil.isSubClass(clz, DataEntity.class)) {
				if (clz == User.class) {
					return new String[] { "address", "nick", "birth", "sex", "signature", "locPrivate",
							"avoidDisturb" };
				} else if (clz == Location.class) {
					return new String[] { "lat", "lon" };
				}else if(clz==Trace.class){
					return new String[]{"uid","date","points"};
				}
			}
		}
		return discoverer.getParameterNames(method);
	}

	private boolean canTest(Method method, String url) {
		Class<?>[] paramtypes = method.getParameterTypes();
		for (Class<?> ptype : paramtypes) {
			if (CommUtil.isSubClass(ptype, ServletRequest.class) || CommUtil.isSubClass(ptype, ServletResponse.class)) {
				return false;
			}
		}
		if (url.contains("/login.") || url.contains("/logout.")) {
			return false;
		}
		if (url.contains("/utils/") || url.contains("/public/") || url.contains("/register.")) {
			return true;
		}
		if (url.contains("/user/list")) {
			return true;
		}
		User user = UserUtils.getCurrentUser();
		if (user.isAdmin()) {
			return false;
		}

		return true;
	}

}